home *** CD-ROM | disk | FTP | other *** search
/ The Atari Compendium / The Atari Compendium (Toad Computers) (1994).iso / files / prgtools / mint / mint108s.zoo / main.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-08-06  |  39.1 KB  |  1,503 lines

  1. /*
  2. Copyright 1990,1991,1992 Eric R. Smith.
  3. Copyright 1992,1993 Atari Corporation.
  4. All rights reserved.
  5. */
  6.  
  7. #include "mint.h"
  8. #include "version.h"
  9. #include "cookie.h"
  10. #include "xbra.h"
  11.  
  12. /* the kernel's stack size */
  13. #define STACK    8*1024L
  14.  
  15. /* if the user is holding down the magic shift key, we ask before booting */
  16. #define MAGIC_SHIFT 0x2        /* left shift */
  17.  
  18. /* magic number to show that we have captured the reset vector */
  19. #define RES_MAGIC 0x31415926L
  20.  
  21. static void xbra_install P_((xbra_vec *, long, long ARGS_ON_STACK (*)()));
  22. static void init_intr P_((void));
  23. static long getmch P_((void));
  24. static void do_line P_((char *));
  25. static void shutmedown P_((PROC *));
  26. void shutdown P_((void));
  27. static void doset P_((char *,char *));
  28. static long ARGS_ON_STACK mint_criticerr P_((long));
  29. static void ARGS_ON_STACK do_exec_os P_((register long basepage));
  30.  
  31. static int gem_active;    /* 0 if AES has not started, nonzero otherwise */
  32.  
  33. #define EXEC_OS 0x4feL
  34. static int  check_for_gem P_((void));
  35. static void run_auto_prgs P_((void));
  36.  
  37. #ifdef LATTICE
  38. /*
  39.  * AGK: this is witchcraft to completely replace the startup code for
  40.  * Lattice; doing so saves around 10K on the final binary and pulls only
  41.  * long division & multitplication from the library (and not even those
  42.  * if you compile for native '030). The drawback of this code is it
  43.  * passes no environment or command line whatsoever. Since I always
  44.  * set MiNT options & environment in 'mint.cnf' this is not a personal
  45.  * downer, however at some point in the future we ought to have a kernel
  46.  * parseargs() like call which sets these things up.
  47.  */ 
  48. BASEPAGE *_base;
  49.  
  50. static void
  51. start(BASEPAGE *bp)
  52. {
  53.     long shrinklen;
  54.     
  55.     _base = bp;
  56.     shrinklen = bp->p_tlen + bp->p_dlen + bp->p_blen + STACK + 0x100;
  57.     if (bp->p_lowtpa + shrinklen <= bp->p_hitpa) {
  58.         static char null[1] = {""};
  59.         static char *argv[2] = {null, NULL};
  60.         extern __builtin_putreg P_((int, long));    /* totally bogus */
  61.  
  62.         __builtin_putreg(15, bp->p_lowtpa + shrinklen);
  63.         Mshrink((void *)bp->p_lowtpa, shrinklen);
  64.         main(1, argv);
  65.     }
  66.     Pterm(ENSMEM);
  67. }
  68. #endif
  69.  
  70. #if defined(__GNUC__) || defined(__MINT__)
  71. long _stksize = STACK;
  72. #ifndef PROFILING
  73. #include <minimal.h>
  74. #endif
  75. #endif
  76.  
  77. int curs_off = 0;    /* set if we should turn the cursor off when exiting */
  78. int mint_errno = 0;    /* error return from open and creat filesystem calls */
  79.  
  80. /*
  81.  * AGK: for proper co-processors we must consider saving their context.
  82.  * This variable when non-zero indicates that the BIOS considers a true
  83.  * coprocessor to be present. We use this variable in the context switch
  84.  * code to decide whether to attempt an FPU context save.
  85.  */
  86. short fpu = 0;
  87.  
  88. /*
  89.  * "mch" holds what kind of machine we are running on
  90.  */
  91. long mch = 0;
  92.  
  93. /*
  94.  * "screen_boundary+1" tells us how screens must be positioned
  95.  * (to a 256 byte boundary on STs, a 16 byte boundary on other
  96.  * machines; actually, 16 bytes is conservative, 4 is probably
  97.  * OK, but it doesn't hurt to be cautious). The +1 is because
  98.  * we're using this as a mask in the ROUND() macro in mem.h.
  99.  */
  100. int screen_boundary = 255;
  101.  
  102. /*
  103.  * variable holds processor type
  104.  */
  105. long mcpu = 0;
  106.  
  107. /*
  108.  * variable holds language preference
  109.  */
  110. int gl_lang = -1;
  111.  
  112. /*
  113.  * variable set if someone has already installed an flk cookie
  114.  */
  115. int flk = 0;
  116.  
  117. /*
  118.  * variable set to 1 if the _VDO cookie indicates Falcon style video
  119.  */
  120. int FalconVideo;
  121.  
  122. /* program to run at startup */
  123. #ifdef MULTITOS
  124. static int init_is_gem = 1;    /* set to 1 if init_prg is GEM */
  125. #else
  126. static int init_is_gem = 0;    /* set to 1 if init_prg is GEM */
  127. #endif
  128. static const char *init_prg = 0;
  129.  
  130. /* note: init_tail is also used as a temporary stack for resets in
  131.  * intr.spp
  132.  */
  133. char init_tail[256];
  134.  
  135. /* initial environment for that program */
  136. static char *init_env = 0;
  137. /* temporary pointer into that environment for setenv */
  138. static char *env_ptr;
  139. /* length of the environment */
  140. static long env_len;
  141.  
  142. /* GEMDOS pointer to current basepage */
  143. BASEPAGE **tosbp;
  144.  
  145. /* pointer to the BIOS keyboard shift variable */
  146. extern char *kbshft;    /* see bios.c */
  147.  
  148. /* version of TOS we're running over */
  149. int tosvers;
  150.  
  151. /* structures for keyboard/MIDI interrupt vectors */
  152. KBDVEC *syskey, oldkey;
  153. xbra_vec old_ikbd;            /* old ikbd vector */
  154.  
  155. /* values the user sees for the DOS, BIOS, and XBIOS vectors */
  156. long save_dos, save_bios, save_xbios;
  157.  
  158. /* values for original system vectors */
  159. xbra_vec old_dos, old_bios, old_xbios, old_timer, old_vbl, old_5ms;
  160. xbra_vec old_criticerr;
  161. xbra_vec old_execos;
  162.  
  163. long old_term;
  164.  
  165. xbra_vec old_resvec;    /* old reset vector */
  166. long old_resval;    /* old reset validation */
  167.  
  168. #ifdef EXCEPTION_SIGS
  169. /* bus error, address error, illegal instruction, etc. vectors */
  170. xbra_vec old_bus, old_addr, old_ill, old_divzero, old_trace, old_priv;
  171. xbra_vec old_linef, old_chk, old_trapv, old_mmuconf, old_format, old_cpv;
  172. xbra_vec old_uninit, old_spurious, old_fpcp[7], old_pmmuill, old_pmmuacc;
  173. #endif
  174.  
  175. /* BIOS disk vectors */
  176. xbra_vec old_mediach, old_getbpb, old_rwabs;
  177.  
  178. /* BIOS drive map */
  179. long olddrvs;
  180.  
  181. extern Func bios_tab[], dos_tab[];
  182.  
  183. /* kernel info that is passed to loaded file systems and device drivers */
  184.  
  185. struct kerinfo kernelinfo = {
  186.     MAJ_VERSION, MIN_VERSION,
  187.     DEFAULT_MODE, 0,
  188.     bios_tab, dos_tab,
  189.     changedrv,
  190.     Trace, Debug, ALERT, FATAL,
  191.     kmalloc, kfree, umalloc, ufree,
  192.     strnicmp, stricmp, strlwr, strupr, ksprintf,
  193.     ms_time, unixtim, dostim,
  194.     nap, sleep, wake, wakeselect,
  195.     denyshare, denylock, addtimeout, canceltimeout
  196. };
  197.  
  198. /* table of processor frame sizes in _words_ (not used on MC68000) */
  199. unsigned char framesizes[16] = {
  200. /*0*/    0,    /* MC68010/M68020/M68030/M68040 short */
  201. /*1*/    0,    /* M68020/M68030/M68040 throwaway */
  202. /*2*/    2,    /* M68020/M68030/M68040 instruction error */
  203. /*3*/    2,    /* M68040 floating point post instruction */
  204. /*4*/    3,    /* MC68LC040/MC68EC040 unimplemented floating point instruction */
  205. /*5*/    0,    /* NOTUSED */
  206. /*6*/    0,    /* NOTUSED */
  207. /*7*/    26,    /* M68040 access error */    
  208. /*8*/    25,    /* MC68010 long */    
  209. /*9*/    6,    /* M68020/M68030 mid instruction */
  210. /*A*/    12,    /* M68020/M68030 short bus cycle */
  211. /*B*/    42,    /* M68020/M68030 long bus cycle */
  212. /*C*/    8,    /* CPU32 bus error */
  213. /*D*/    0,    /* NOTUSED */
  214. /*E*/    0,    /* NOTUSED */
  215. /*F*/    13    /* 68070 and 9xC1xx microcontroller address error */
  216. };
  217.  
  218. /* TOS and MiNT cookie jars, respectively. See the comments and code 
  219.  * after main() for further details
  220.  */
  221.  
  222. COOKIE *oldcookie, *newcookie;
  223.  
  224. /*
  225.  * install a new vector for address "addr", using the XBRA protocol.
  226.  * must run in supervisor mode!
  227.  */
  228.  
  229. static void
  230. xbra_install(xv, addr, func)
  231.     xbra_vec *xv;
  232.     long addr;
  233.     long ARGS_ON_STACK (*func)();
  234. {
  235.     xv->xbra_magic = XBRA_MAGIC;
  236.     xv->xbra_id = MINT_MAGIC;
  237.     xv->jump = JMP_OPCODE;
  238.     xv->this = func;
  239.     xv->next = *((struct xbra **)addr);
  240.     *((short **)addr) = &xv->jump;
  241. }
  242.  
  243. /*
  244.  * MiNT critical error handler; all it does is to jump through
  245.  * the vector for the current process
  246.  */
  247.  
  248. static long ARGS_ON_STACK
  249. mint_criticerr(error)
  250.     long error;    /* high word is error, low is drive */
  251. {
  252.     return (*curproc->criticerr)(error);
  253. }
  254.  
  255. /*
  256.  * if we are MultiTOS, and if we are running from the AUTO folder,
  257.  * then we grab the exec_os vector and use that to start GEM; that
  258.  * way programs that expect exec_os to act a certain way will still
  259.  * work.
  260.  * NOTE: we must use Pexec instead of p_exec here, because we will
  261.  * be running in a user context (that of process 1, not process 0)
  262.  */
  263.  
  264. static void ARGS_ON_STACK
  265. do_exec_os(basepage)
  266.     register long basepage;
  267. {
  268.     register long r;
  269.  
  270. /* if the user didn't specify a startup program, jump to the ROM */
  271.     if (!init_prg) {
  272.         register void ARGS_ON_STACK (*f) P_((long));
  273.         f = (void ARGS_ON_STACK (*) P_((long))) old_execos.next;
  274.         (*f)(basepage);
  275.         Pterm0();
  276.     } else {        
  277.  
  278. /* we have to set a7 to point to lower in our TPA; otherwise we would
  279.  * bus error right after the Mshrink call!
  280.  */
  281.         setstack(basepage+500L);
  282. #if defined(__TURBOC__) && !defined(__MINT__)
  283.         Mshrink(0, (void *)basepage, 512L);
  284. #else
  285.         Mshrink((void *)basepage, 512L);
  286. #endif
  287.         r = Pexec(200, (char *)init_prg, init_tail, init_env);
  288.         Pterm((int)r);
  289.     }
  290. }
  291.  
  292.  
  293. /* initialize all interrupt vectors and new trap routines
  294.  * we also get here any TOS variables that we're going to change
  295.  * (e.g. the pointer to the cookie jar) so that rest_intr can
  296.  * restore them.
  297.  */
  298.  
  299. static void
  300. init_intr()
  301. {
  302.     extern long ARGS_ON_STACK mint_bios();
  303.     extern long ARGS_ON_STACK mint_dos();
  304.     extern long ARGS_ON_STACK mint_timer();
  305.     extern long ARGS_ON_STACK mint_vbl();
  306.     extern long ARGS_ON_STACK mint_5ms();
  307.     extern long ARGS_ON_STACK mint_xbios();
  308.     extern long ARGS_ON_STACK reset();
  309.       extern long ARGS_ON_STACK new_ikbd();
  310.       extern long ARGS_ON_STACK new_bus();
  311.       extern long ARGS_ON_STACK new_addr();
  312.       extern long ARGS_ON_STACK new_ill();
  313.       extern long ARGS_ON_STACK new_divzero();
  314.       extern long ARGS_ON_STACK new_trace();
  315.       extern long ARGS_ON_STACK new_priv();
  316.       extern long ARGS_ON_STACK new_linef();
  317.       extern long ARGS_ON_STACK new_chk();
  318.       extern long ARGS_ON_STACK new_trapv();
  319.       extern long ARGS_ON_STACK new_fpcp();
  320.       extern long ARGS_ON_STACK new_mmu();
  321.       extern long ARGS_ON_STACK new_format();
  322.       extern long ARGS_ON_STACK new_cpv();
  323.       extern long ARGS_ON_STACK new_uninit();
  324.       extern long ARGS_ON_STACK new_spurious();
  325.       extern long ARGS_ON_STACK new_pmmuacc();
  326.     short savesr;
  327.     int i;
  328.  
  329.     syskey = (KBDVEC *)Kbdvbase();
  330.     oldkey = *syskey;
  331.  
  332.     xbra_install(&old_ikbd, (long)(&syskey->ikbdsys), new_ikbd);
  333.  
  334. /* gratuitous (void *) for Lattice */
  335.     old_term = (long)Setexc(0x102, (void *)-1UL);
  336.  
  337.     savesr = spl7();
  338.  
  339.     xbra_install(&old_dos, 0x84L, mint_dos);
  340.     save_dos = (long)old_dos.next;
  341.  
  342.     xbra_install(&old_bios, 0xb4L, mint_bios);
  343.     save_bios = (long)old_bios.next;
  344.  
  345.     xbra_install(&old_xbios, 0xb8L, mint_xbios);
  346.     save_xbios = (long)old_xbios.next;
  347.  
  348.     xbra_install(&old_timer, 0x400L, mint_timer);
  349.     xbra_install(&old_criticerr, 0x404L, mint_criticerr);
  350.     xbra_install(&old_5ms, 0x114L, mint_5ms);
  351.     xbra_install(&old_vbl, 4*0x1cL, mint_vbl);
  352.     xbra_install(&old_resvec, 0x42aL, reset);
  353.     old_resval = *((long *)0x426L);
  354.     *((long *)0x426L) = RES_MAGIC;
  355.  
  356.     spl(savesr);
  357.  
  358. #ifdef EXCEPTION_SIGS
  359. /* set up signal handlers */
  360.     xbra_install(&old_bus, 8L, new_bus);
  361.     xbra_install(&old_addr, 12L, new_addr);
  362.     xbra_install(&old_ill, 16L, new_ill);
  363.     xbra_install(&old_divzero, 20L, new_divzero);
  364.     xbra_install(&old_trace, 36L, new_trace);
  365.     xbra_install(&old_priv, 32L, new_priv);
  366.     if (tosvers >= 0x106)
  367.         xbra_install(&old_linef, 44L, new_linef);
  368.     xbra_install(&old_chk, 24L, new_chk);
  369.     xbra_install(&old_trapv, 28L, new_trapv);
  370.     for (i = (int)(sizeof(old_fpcp) / sizeof(old_fpcp[0])); i--; ) {
  371.         xbra_install(&old_fpcp[i], 192L + i * 4, new_fpcp);
  372.     }
  373.     xbra_install(&old_mmuconf, 224L, new_mmu);
  374.     xbra_install(&old_pmmuill, 228L, new_mmu);
  375.     xbra_install(&old_pmmuacc, 232L, new_pmmuacc);
  376.     xbra_install(&old_format, 56L, new_format);
  377.     xbra_install(&old_cpv, 52L, new_cpv);
  378.     xbra_install(&old_uninit, 60L, new_uninit);
  379.     xbra_install(&old_spurious, 96L, new_spurious);
  380. #endif
  381.  
  382. /* set up disk vectors */
  383.     xbra_install(&old_mediach, 0x47eL, new_mediach);
  384.     xbra_install(&old_rwabs, 0x476L, new_rwabs);
  385.     xbra_install(&old_getbpb, 0x472L, new_getbpb);
  386.     olddrvs = *((long *)0x4c2L);
  387.  
  388. /* set up cookie jar */
  389.     oldcookie = *CJAR;    /* CJAR defined in cookie.h */
  390.     install_cookies();
  391. }
  392.  
  393. /* restore all interrupt vectors and trap routines */
  394. /*
  395.  * NOTE: This is *not* the approved way of unlinking XBRA trap handlers.
  396.  * Normally, one should trace through the XBRA chain. However, this is
  397.  * a very unusual situation: when MiNT exits, any TSRs or programs running
  398.  * under MiNT will no longer exist, and so any vectors that they have
  399.  * caught will be pointing to never-never land! So we do something that
  400.  * would normally be considered rude, and restore the vectors to
  401.  * what they were before we ran.
  402.  * BUG: we should restore *all* vectors, not just the ones that MiNT caught.
  403.  */
  404.  
  405. void
  406. restr_intr()
  407. {
  408.     short savesr;
  409.     int i;
  410.  
  411.     savesr = spl7();
  412.     *syskey = oldkey;        /* restore keyboard vectors */
  413.     *tosbp = _base;            /* restore GEMDOS basepage pointer */
  414.     *CJAR = oldcookie;        /* restore old cookie jar */
  415.  
  416. #ifdef EXCEPTION_SIGS
  417.     *((long *)0x08L) = (long) old_bus.next;
  418.     *((long *)0x0cL) = (long) old_addr.next;
  419.     *((long *)0x10L) = (long) old_ill.next;
  420.     *((long *)0x14L) = (long) old_divzero.next;
  421.     *((long *)0x20L) = (long) old_priv.next;
  422.     *((long *)0x24L) = (long) old_trace.next;
  423.     if (old_linef.next)
  424.         *((long *)0x2cL) = (long) old_linef.next;
  425.     *((long *)0x18L) = (long) old_chk.next;
  426.     *((long *)0x1cL) = (long) old_trapv.next;
  427.     for (i = (int)(sizeof(old_fpcp) / sizeof(old_fpcp[0])); i--; ) {
  428.         ((long *)0xc0L)[i] = (long) old_fpcp[i].next;
  429.     }
  430.     *((long *)0xe0L) = (long) old_mmuconf.next;
  431.     *((long *)0xe4L) = (long) old_pmmuill.next;
  432.     *((long *)0xe8L) = (long) old_pmmuacc.next;
  433.     *((long *)0x38L) = (long) old_format.next;
  434.     *((long *)0x34L) = (long) old_cpv.next;
  435.     *((long *)0x3cL) = (long) old_uninit.next;
  436.     *((long *)0x60L) = (long) old_spurious.next;
  437. #endif
  438.     *((long *)0x84L) = (long) old_dos.next;
  439.     *((long *)0xb4L) = (long) old_bios.next;
  440.     *((long *)0xb8L) = (long) old_xbios.next;
  441.     *((long *)0x408L) = old_term;
  442.     *((long *)0x404L) = (long) old_criticerr.next;
  443.     *((long *)0x114L) = (long) old_5ms.next;
  444.     *((long *)0x400L) = (long) old_timer.next;
  445.     *((long *)0x70L) = (long) old_vbl.next;
  446.     *((long *)0x426L) = old_resval;
  447.     *((long *)0x42aL) = (long) old_resvec.next;
  448.     *((long *)0x476L) = (long) old_rwabs.next;
  449.     *((long *)0x47eL) = (long) old_mediach.next;
  450.     *((long *)0x472L) = (long) old_getbpb.next;
  451.     *((long *)0x4c2L) = olddrvs;
  452.  
  453.     spl(savesr);
  454. }
  455.  
  456.  
  457. /* we save the TOS supervisor stack pointer so that we can reset it when
  458.    calling Pterm() (not that anyone will ever want to leave MiNT :-)).
  459.  */
  460.  
  461. long tosssp;        /* TOS supervisor stack pointer */
  462.  
  463.  
  464. /*
  465.  * enter_kernel: called every time we enter the MiNT kernel via a trap
  466.  * call. Sets up the GEMDOS and BIOS vectors to point to TOS, and
  467.  * sets up other vectors and system variables appropriately. Note that
  468.  * calling enter_kernel multiple times is probably NOT a good idea,
  469.  * but the code will allow it.
  470.  */
  471.  
  472. short in_kernel = 0;
  473.  
  474. void ARGS_ON_STACK
  475. enter_kernel()
  476. {
  477.     short save_sr;
  478.  
  479.     if (in_kernel) return;
  480.  
  481.     save_sr = spl7();
  482.     save_dos = *((long *) 0x84L);
  483.     save_bios = *((long *) 0xb4L);
  484.     save_xbios = *((long *) 0xb8L);
  485.     *((long *) 0x84L) = (long)old_dos.next;
  486.     *((long *) 0xb4L) = (long)old_bios.next;
  487.     *((long *) 0xb8L) = (long)old_xbios.next;
  488.     *tosbp = _base;
  489.  
  490.     in_kernel = 1;
  491.     spl(save_sr);
  492. }
  493.  
  494. /*
  495.  * leave_kernel: called before leaving the kernel, either back to
  496.  * user mode or when calling a signal handler or the GEMDOS
  497.  * terminate vector. Note that interrupts should be disabled before
  498.  * this routine is called.
  499.  */
  500.  
  501. void ARGS_ON_STACK
  502. leave_kernel()
  503. {
  504.     *((long *) 0x84L) = save_dos;
  505.     *((long *) 0xb4L) = save_bios;
  506.     *((long *) 0xb8L) = save_xbios;
  507.     *tosbp = curproc->base;
  508.     in_kernel = 0;
  509. }
  510.  
  511. /*
  512.  * shut down processes; this involves waking them all up, and sending
  513.  * them SIGTERM to give them a chance to clean up after themselves
  514.  */
  515.  
  516. static void
  517. shutmedown(p)
  518.     PROC *p;
  519. {
  520.     UNUSED(p);
  521.     curproc->wait_cond = 0;
  522. }
  523.  
  524. void
  525. shutdown()
  526. {
  527.     PROC *p;
  528.     int proc_left = 0;
  529.  
  530.     curproc->sighandle[SIGCHLD] = SIG_IGN;
  531.  
  532.     for (p = proclist; p; p = p->gl_next) {
  533.         if (p->pid == 0) continue;
  534.         if (p->wait_q != ZOMBIE_Q && p->wait_q != TSR_Q) {
  535.             if (p->wait_q != READY_Q) {
  536.                 short sr = spl7();
  537.                 rm_q(p->wait_q, p);
  538.                 add_q(READY_Q, p);
  539.                 spl(sr);
  540.             }
  541.             post_sig(p, SIGTERM);
  542.             proc_left++;
  543.         }
  544.     }
  545.  
  546.     if (proc_left) {
  547.         /* sleep a little while, to give the other processes a chance to
  548.            shut down
  549.          */
  550.  
  551.         addtimeout(1000, shutmedown);
  552.         do {
  553.             sleep(WAIT_Q, (long)shutdown);
  554.         } while (curproc->wait_cond == (long)shutdown);
  555.     }
  556. }
  557.  
  558. #if defined(__GNUC__) || defined(__MINT__)
  559. int
  560. main(argc, argv, envp)
  561.     int argc;
  562.     char **argv, **envp;
  563. #else
  564. int
  565. main(argc, argv)
  566.     int argc;
  567.     char **argv;
  568. #endif
  569. {
  570.     long *sysbase;
  571.     long r;
  572.     extern int debug_level, debug_logging;    /* in debug.c */
  573.     extern int no_mem_prot;        /* memprot.c */
  574.     extern const char *greet1, *greet2;
  575.                     /* welcome.c */
  576.     static char buf[SPRINTF_MAX];
  577.     static char curpath[128];
  578.     long yn;
  579.     FILEPTR *f;
  580.  
  581. #if defined(__GNUC__) || defined(__MINT__)
  582.     UNUSED(envp);
  583. #endif
  584.  
  585. /* figure out what kind of machine we're running on */
  586. /* biosfs wants to know this; also sets no_mem_prot */
  587. /* 920625 kbad put it here so memprot_warning can be intelligent */
  588.     (void)Supexec(getmch);
  589. #ifdef ONLY030
  590.     if (mcpu != 30) {
  591.         Cconws("\r\nThis version of MiNT requires a 68030.\r\n");
  592.         Cconws("Hit any key to continue.\r\n");
  593.         (void)Cconin();
  594.         Pterm0();
  595.     }
  596. #endif
  597.  
  598. #ifdef MULTITOS
  599. /* Ask the user if s/he wants to boot MultiTOS or regular TOS */
  600.     if ((Kbshift(-1) & MAGIC_SHIFT) == MAGIC_SHIFT) {
  601.         yn = boot_kernel_p();
  602.         Cconws("\r\n");
  603.         if (!yn)
  604.             Pterm0();
  605.     }
  606. #else
  607. /* Allow the user to abort the boot if the magic combination of shift keys
  608.  * is held down (see MAGIC_SHIFT above)
  609.  */
  610.     if ((Kbshift(-1) & MAGIC_SHIFT) == MAGIC_SHIFT) {
  611.         Cconws("Boot MiNT? (y/n) ");
  612.         yn = Cconin() & 0x7f;
  613.         if (yn != 'y' && yn != 'Y') {
  614.             Cconws("\r\n\r\nMiNT not booted, at user's request.\r\n");
  615.             Pterm0();
  616.         }
  617.     }
  618. #endif
  619.  
  620.     if (argv[0][0] == 0) {    /* maybe started from the desktop */
  621.         curs_off = 1;
  622.     }
  623.  
  624.     yn = 0; /* by default, don't print basepage */
  625.     --argc, ++argv;
  626.     while (argc && **argv == '-') {
  627.         if (argv[0][1] >= '0' && argv[0][1] <= '9') {
  628.         /* a number sets out_device to that device */
  629.             extern int out_device;
  630.             out_device = (int)atol(&argv[0][1]);
  631.         }
  632.         else if (argv[0][1] == 'b') {
  633.         /* print MiNT basepage */
  634.             yn++;
  635.         }
  636.         else if (argv[0][1] == 'd') {
  637.         /* -d increases debugging level */
  638.             debug_level++;
  639.         }
  640.         else if (argv[0][1] == 'm' || argv[0][1] == 'p') {
  641.             int givenotice = (argv[0][2] != 'w');
  642.         /* -m and -p turn off memory protection */
  643.         extern const char *memprot_notice, *memprot_warning;
  644.             if (no_mem_prot) {
  645.                 if (givenotice)
  646.                 Cconws(memprot_notice);
  647.             }
  648.             else {
  649.                 no_mem_prot = 1;
  650.                 if (givenotice)
  651.                 Cconws(memprot_warning);
  652.             }
  653.         }
  654.         else if (argv[0][1] == 'l') {
  655.         /* -l turns on debug logging */
  656.             debug_logging = 1;
  657.         }
  658.         else {
  659.             Cconws("Unknown argument (ignored): ");
  660.             Cconws(*argv);
  661.             Cconws("\r\n");
  662.         }
  663.         ++argv, --argc;
  664.     }
  665.     if (argc) {
  666.         Cconws("Unknown argument ignored: ");
  667.         Cconws(*argv);
  668.         Cconws(" (and all the rest)\r\n");
  669.         }
  670.  
  671. /* greetings */
  672.     Cconws(greet1);
  673.     ksprintf(buf, VERS_STRING, MAJ_VERSION, MIN_VERSION);
  674.     Cconws(buf);
  675.     Cconws(greet2);
  676.  
  677. #ifdef __TURBOC__
  678.     Cconws("PRELIMINARY PureC compiled version!\r\n");
  679. #endif
  680.  
  681.     if (yn)
  682.     {
  683.             ksprintf(buf,"MiNT@%lx\r\nhit a key...",_base);
  684.         Cconws(buf);
  685.         (void)Crawcin();
  686.         Cconws("\r\033K");
  687.     }
  688.  
  689. #ifdef notdef
  690. /* if less than 1 megabyte free, turn off memory protection */
  691.     if (Mxalloc(-1L, 3) < ONE_MEG && !no_mem_prot) {
  692.         extern const char *insuff_mem_warning;
  693.         Cconws(insuff_mem_warning);
  694.         no_mem_prot = 1;
  695.     }
  696. #endif
  697.  
  698. /* look for ourselves as \AUTO\MINTNP.PRG; if so, we turn memory
  699.  * protection off
  700.  */
  701.     if (!no_mem_prot && Fsfirst("\\AUTO\\MINTNP.PRG",0) == 0)
  702.         no_mem_prot = 1;
  703.  
  704. /* check for GEM -- this must be done from user mode */
  705.     gem_active = check_for_gem();
  706.  
  707. /*
  708.  * get the current directory, so that we can switch back to it after
  709.  * the file systems are properly initialized
  710.  */
  711. /* set the current directory for the current process */
  712.     (void)Dgetpath(curpath, 0);
  713.     if (!*curpath) {
  714.         curpath[0] = '\\';
  715.         curpath[1] = 0;
  716.     }
  717.     tosssp = (long)Super(0L);    /* enter supervisor mode */
  718.     if (!no_mem_prot)
  719.         save_mmu();        /* save current MMU setup */
  720.  
  721. /* get GEMDOS pointer to current basepage */
  722. /* 0x4f2 points to the base of the OS; here we can find the OS compilation
  723.    date, and (in newer versions of TOS) where the current basepage pointer
  724.    is kept; in older versions of TOS, it's at 0x602c
  725.  */
  726.     sysbase = *((long **)(0x4f2L));    /* gets the RAM OS header */
  727.     sysbase = (long *)sysbase[2];    /* gets the ROM one */
  728.  
  729.     tosvers = (int)(sysbase[0] & 0x0000ffff);
  730.     if (tosvers == 0x100) {
  731.         if ((sysbase[7] & 0xfffe0000L) == 0x00080000L)
  732.             tosbp = (BASEPAGE **)0x873cL;    /* SPANISH ROM */
  733.         else
  734.             tosbp = (BASEPAGE **) 0x602cL;
  735.         kbshft = (char *) 0x0e1bL;
  736.     } else {
  737.         tosbp = (BASEPAGE **) sysbase[10];
  738.         kbshft = (char *) sysbase[9];
  739.     }
  740.  
  741.     if (tosvers >= 0x0400 && tosvers <= 0x404)
  742.         has_bconmap = 0;    /* Falcon BIOS Bconmap is busted */
  743.     else
  744. /* The TT TOS release notes are wrong... this is the real way to test
  745.  * for Bconmap ability
  746.  */
  747.         has_bconmap = (Bconmap(0) == 0);
  748.  
  749. /* initialize memory */
  750.     init_mem();
  751.  
  752. /* initialize the basic file systems */
  753.     init_filesys();
  754.  
  755. /* initialize processes */
  756.     init_proc();
  757.  
  758. /* initialize system calls */
  759.     init_dos();
  760.     init_bios();
  761.     init_xbios();
  762.  
  763. /* NOTE: there's a call to kmalloc embedded in install_cookies, which
  764.  * is called by init_intr; so make sure this is the last of the
  765.  * init_* things called!
  766.  */
  767.     init_intr();
  768.     enter_kernel();
  769.  
  770.     if (!gem_active) {
  771. /* make MiNT invisible in the basepage chain, so that
  772.  * programs that rely on a certain basepage chain
  773.  * structure to determine whether or not they were run
  774.  * from the desktop will have a better chance of working.
  775.  * NOTE THAT THIS IS ONLY DONE TO HELP OUT BRAIN-DAMAGED
  776.  * SOFTWARE: do *not* try counting basepages to figure
  777.  * out whether or not you were run from the desktop!!!
  778.  */
  779.         rootproc->base = _base->p_parent;
  780.     }
  781.  
  782. /* set up standard file handles for the current process
  783.  * do this here, *after* init_intr has set the Rwabs vector,
  784.  * so that AHDI doesn't get upset by references to drive U:
  785.  */
  786.     f = do_open("U:\\DEV\\CONSOLE", O_RDWR, 0, (XATTR *)0);
  787.     if (!f) {
  788.         FATAL("unable to open CONSOLE device");
  789.     }
  790.     curproc->control = f;
  791.     curproc->handle[0] = f;
  792.     curproc->handle[1] = f;
  793.     f->links = 3;
  794.  
  795.     f = do_open("U:\\DEV\\MODEM1", O_RDWR, 0, (XATTR *)0);
  796.     curproc->aux = f;
  797.     if (has_bconmap) {
  798.     /* If someone has already done a Bconmap call, then
  799.      * MODEM1 may no longer be the default
  800.      */
  801.         bconmap(curbconmap);
  802.         f = curproc->aux;    /* bconmap can change curproc->aux */
  803.     }
  804.     if (f) {
  805.         curproc->handle[2] = f;
  806.         f->links++;
  807.     }
  808.     f = do_open("U:\\DEV\\CENTR", O_RDWR, 0, (XATTR *)0);
  809.     if (f) {
  810.         curproc->handle[3] = curproc->prn = f;
  811.         f->links = 2;
  812.     }
  813.     if (f) {
  814.         f = do_open("U:\\DEV\\MIDI", O_RDWR, 0, (XATTR *)0);
  815.         curproc->midiin = curproc->midiout = f;
  816.         f->links = 2;
  817.     }
  818.  
  819. /* load external file systems */
  820. /* set path first to make sure that MiNT's directory matches
  821.  * GEMDOS's
  822.  */
  823.     (void)d_setpath(curpath);
  824.     
  825.     load_devdriver();
  826.  
  827. #ifndef PROFILING
  828. /* load_filesys causes media changes :-( */
  829.     load_filesys();
  830. #endif
  831.  
  832. /* note that load_filesys changed the
  833.  * directory on us!!
  834.  */
  835.     (void)d_setpath(curpath);
  836.     
  837. /* load the configuration file */
  838.     load_config();
  839.  
  840.     *((long *)0x4c2L) |= PSEUDODRVS;
  841.  
  842.     if (init_env == 0)
  843.         init_env = (char *)_base->p_env;
  844.  
  845. /* empty environment? Set the PATH variable to the root of the current drive */
  846.     if (init_env[0] == 0) {
  847.         static char path_env[] = "PATH=\0C:\0";
  848.         path_env[6] = curproc->curdrv + 'A';
  849.         init_env = path_env;
  850.     }
  851.  
  852. /* if we are MultiTOS, we're running in the AUTO folder, and our INIT is
  853.  * in fact GEM, take the exec_os() vector. (We know that INIT is GEM
  854.  * if the user told us so by using GEM= instead of INIT=.)
  855.  */
  856.     if (!gem_active && init_is_gem) {
  857.         xbra_install(&old_execos, EXEC_OS, (long ARGS_ON_STACK (*)())do_exec_os);
  858.     }
  859.  
  860. /* run any programs appearing after us in the AUTO folder */
  861.     run_auto_prgs();
  862.  
  863. /* run the initial program */
  864. /* if that program is in fact GEM, we start it via exec_os, otherwise
  865.  * we do it with Pexec.
  866.  * the logic is: if the user specified init_prg, and it is not
  867.  * GEM, then we try to execute it; if it *is* GEM (e.g. gem.sys),
  868.  * then we try to execute it if gem is already active, otherwise
  869.  * we jump through the exec_os vector (which we grabbed above) in
  870.  * order to start it. We *never* go through exec_os if we're not in
  871.  * the AUTO folder.
  872.  */
  873.     if (init_prg && (!init_is_gem || gem_active)) {
  874.         r = p_exec(0, (char *)init_prg, init_tail, init_env);
  875.     } else if (!gem_active) {   
  876.         BASEPAGE *bp; int pid;
  877.         bp = (BASEPAGE *)p_exec(7,
  878.           (char *)((long)F_FASTLOAD | F_ALTLOAD | F_ALTALLOC | F_PROT_S),
  879.           (char *)"\0", init_env);
  880.         bp->p_tbase = *((long *) EXEC_OS );
  881.         r = p_exec(106, (char *)"GEM", bp, 0L);
  882.         pid = (int)r;
  883.         if (pid > 0) {
  884.             do {
  885.                 r = p_wait3(0, (long *)0);
  886.             } while(pid != ((r & 0xffff0000L) >> 16));
  887.             r &= 0x0000ffff;
  888.         }
  889.     } else {
  890. Cconws("If MiNT is run after GEM starts, you must specify a program\r\n");
  891. Cconws("to run initially in MINT.CNF, with an INIT= line\r\n");
  892.             r = 0;
  893.     }
  894.  
  895.     if (r < 0 && init_prg) {
  896.         ksprintf(buf, "FATAL: couldn't run %s\r\n", init_prg);
  897.         Cconws(buf);
  898.     }
  899.  
  900.     if (r) {
  901.         ksprintf(buf, "exit code: %ld\r\n", r);
  902.         Cconws(buf);
  903.     }
  904.  
  905.     rootproc->base = _base;
  906.  
  907. /* shut down all processes gracefully */
  908.     shutdown();
  909.  
  910. /* put everything back and exit */
  911.     if (!gem_active && init_is_gem) {
  912.     /* we stole exec_os above */
  913.         *((long *)EXEC_OS) = (long)old_execos.next;
  914.     }
  915.     restr_intr();
  916.     close_filesys();
  917.     if (!no_mem_prot)
  918.         restr_mmu();
  919.  
  920.     (void)Super((void *)tosssp);    /* gratuitous (void *) for Lattice */
  921.     Cconws("leaving MiNT\r\n");
  922.  
  923.     if (curs_off)
  924.         Cconws("\033f");    /* disable cursor */
  925.  
  926.     return 0;
  927. }
  928.  
  929.  
  930. /*
  931.  * cookie jar handling routines. The "cookie jar" is an area of memory
  932.  * reserved by TOS for TSR's and utility programs; the idea is that
  933.  * you put a cookie in the jar to notify people of available services.
  934.  * The BIOS uses the cookie jar in TOS 1.6 and higher; for earlier versions
  935.  * of TOS, the jar is always empty (unless someone added a cookie before
  936.  * us; POOLFIX does, for example).
  937.  * MiNT establishes an entirely new cookie jar (with the old cookies copied
  938.  * over) and frees it on exit. That's because TSR's run under MiNT
  939.  * will no longer be accessible after MiNT exits.
  940.  * MiNT also puts a cookie in the jar, with tag field 'MiNT' (of course)
  941.  * and with the major version of MiNT in the high byte of the low word,
  942.  * and the minor version in the low byte.
  943.  */
  944.  
  945. void
  946. install_cookies()
  947. {
  948.     COOKIE *cookie;
  949.     int i, ncookies;
  950.     long ncsize;
  951.  
  952.     /* note that init_intr sets oldcookie to the old cookie jar */
  953.  
  954.     ncookies = 0;
  955.     cookie = oldcookie;
  956.     if (cookie) {
  957.         while (cookie->tag.aslong != 0) {
  958.         /* check for true FPU co-processor */
  959.             if (!strncmp(cookie->tag.aschar, "_FPU",4) &&
  960.                  (cookie->value >> 16) >= 2)
  961.                 fpu = 1;
  962.         /* check for _FLK cookie */
  963.             else if (!strncmp(cookie->tag.aschar, "_FLK",4))
  964.                 flk = 1;
  965.             cookie++; ncookies++;
  966.         }
  967.     }
  968.  
  969.     /*
  970.      * We allocate the cookie jar in global memory so anybody can read
  971.      * it or write it. This code allocates at least 8 more cookies, and
  972.      * then rounds up to a QUANTUM boundary (that's what ROUND does). 
  973.      * Probably, nobody will have to allocate another cookie jar :-)
  974.      */
  975.  
  976.     /* NOTE: obviously, we can do this only if init_intr is called
  977.      * _after_ memory, processes, etc. have been initialized
  978.      */
  979.     ncsize = (ncookies+8)*sizeof(COOKIE);
  980.     ncsize = ROUND(ncsize);
  981.     newcookie = (COOKIE *)alloc_region(core, ncsize, PROT_G);
  982.  
  983. /* copy the old cookies to the new jar */
  984.  
  985.     for (i = 0; i < ncookies; i++) {
  986.         newcookie[i] = oldcookie[i];
  987.     }
  988.  
  989. /* install MiNT cookie */
  990.     strncpy(newcookie[i].tag.aschar, "MiNT", 4);
  991.     newcookie[i].value = (MAJ_VERSION << 8) | MIN_VERSION;
  992.     i++;
  993.  
  994. /* install _FLK cookie to indicate that file locking works */
  995.     if (!flk) {
  996.         strncpy(newcookie[i].tag.aschar, "_FLK", 4);
  997.         newcookie[i].value = 0;
  998.         i++;
  999.     }
  1000.  
  1001. /* jr: install PMMU cookie if memory protection is used */
  1002.     if (!no_mem_prot) {
  1003.         strncpy(newcookie[i].tag.aschar, "PMMU", 4);
  1004.         newcookie[i].value = 0;
  1005.         i++;
  1006.     }
  1007.  
  1008. /* the last cookie should have a 0 tag, and a value indicating the number
  1009.  * of slots, total
  1010.  */
  1011.  
  1012.     newcookie[i].tag.aslong = 0;
  1013.     newcookie[i].value = ncsize/sizeof(COOKIE);
  1014.  
  1015.     *CJAR = newcookie;
  1016.  
  1017. }
  1018.  
  1019. /*
  1020.  * Get the value of the _MCH cookie, if one exists; also set no_mem_prot if
  1021.  * there's a _CPU cookie and you're not on an '030, or if there is none.
  1022.  * This must be done in a separate routine because the machine type and CPU
  1023.  * type are needed when initializing the system, whereas install_cookies is
  1024.  * not called until everything is practically up.
  1025.  * In fact, getmch() should be called before *anything* else is
  1026.  * initialized, so that if we find a MiNT cookie already in the
  1027.  * jar we can bail out early and painlessly.
  1028.  */
  1029.  
  1030. static long
  1031. getmch()
  1032. {
  1033.     COOKIE *jar;
  1034.     int foundcpu = 0;
  1035.     int i;
  1036.     long *sysbase;
  1037.     extern int no_mem_prot;
  1038.  
  1039.     mcpu = 0;
  1040.     jar = *CJAR;    /* CJAR defined in cookie.h */
  1041.     if (jar) {
  1042.         while (jar->tag.aslong != 0) {
  1043.         /* check for machine type */
  1044.             if (!strncmp(jar->tag.aschar, "_MCH",4)) {
  1045.                 mch = jar->value;
  1046.             } else if (!strncmp(jar->tag.aschar, "_CPU",4)) {
  1047.                     /* if not '030 then no memory protection */
  1048.                 mcpu = jar->value;
  1049.                     if (jar->value != 30) no_mem_prot = 1;
  1050.                     foundcpu = 1;
  1051.             } else if (!strncmp(jar->tag.aschar, "_VDO",4)) {
  1052.                 FalconVideo = (jar->value == 0x00030000L);
  1053.                 if (jar->value & 0xffff0000L)
  1054.                     screen_boundary = 15;
  1055.             } else if (!strncmp(jar->tag.aschar, "MiNT",4)) {
  1056.                 Cconws("MiNT is already installed!!\r\n");
  1057.                 Pterm(2);
  1058.             } else if (!strncmp(jar->tag.aschar, "_AKP",4)) {
  1059.                 gl_lang = (int) ((jar->value >> 8) & 0x00ff);
  1060.             } else if (!strncmp(jar->tag.aschar, "PMMU",4)) {
  1061.                 /* jr: if PMMU cookie exists, someone else is
  1062.                    already using the PMMU */
  1063.                 Cconws ("MiNT: PMMU already in use, memory protection turned off.\r\n");
  1064.                 no_mem_prot = 1;
  1065.             }
  1066.             jar++;
  1067.         }
  1068.     }
  1069.     if (!foundcpu) no_mem_prot = 1;
  1070. /*
  1071.  * if no preference found, look at the country code to decide
  1072.  */
  1073.     if (gl_lang < 0) {
  1074.         sysbase = *((long **)(0x4f2L)); /* gets the RAM OS header */
  1075.         sysbase = (long *)sysbase[2];    /* gets the ROM one */
  1076.         i = (int) ((sysbase[7] & 0x7ffe0000L) >> 17L);
  1077.         switch(i) {
  1078.         case 1:        /* Germany */
  1079.         case 8:        /* Swiss German */
  1080.             gl_lang = 1;
  1081.             break;
  1082.         case 2:        /* France */
  1083.         case 7:        /* Swiss French */
  1084.             gl_lang = 2;
  1085.             break;
  1086.         case 4:        /* Spain */
  1087.             gl_lang = 4;
  1088.             break;
  1089.         case 5:        /* Italy */
  1090.             gl_lang = 5;
  1091.             break;
  1092.         default:
  1093.             gl_lang = 0;
  1094.             break;
  1095.         }
  1096.     }
  1097.     
  1098.  
  1099.     if (gl_lang >= MAXLANG || gl_lang < 0)
  1100.         gl_lang = 0;
  1101.     return 0L;
  1102. }
  1103.  
  1104. /*
  1105.  * routines for reading the configuration file
  1106.  * we allow the following commands in the file:
  1107.  * # anything        -- comment
  1108.  * INIT=file        -- specify boot program
  1109.  * CON=file        -- specify initial file/device for handles -1, 0, 1
  1110.  * PRN=file        -- specify initial file for handle 3
  1111.  * BIOSBUF=[yn]        -- if 'n' or 'N' then turn off BIOSBUF feature
  1112.  * DEBUG_LEVEL=n    -- set debug level to (decimal number) n
  1113.  * DEBUG_DEVNO=n    -- set debug device number to (decimal number) n
  1114.  * HARDSCROLL=n        -- set hard-scroll size to n, range 0-99.
  1115.  * SLICES=nnn        -- set multitasking granularity
  1116.  * echo message        -- print a message on the screen
  1117.  * alias drive path    -- make a fake drive pointing at a path
  1118.  * cd dir        -- change directory/drive
  1119.  * exec cmd args    -- execute a program
  1120.  * setenv name val    -- set up environment
  1121.  * sln file1 file2    -- create a symbolic link
  1122.  * ren file1 file2    -- rename a file
  1123.  *
  1124.  * BUG: if you use setenv in mint.cnf, *none* of the original environment
  1125.  * gets passed to children. This is rarely a problem if mint.prg is
  1126.  * in the auto folder.
  1127.  */
  1128.  
  1129. extern short bconbdev, bconbsiz;    /* from bios.c */
  1130.  
  1131. static void
  1132. doset(name, val)
  1133.     char *name, *val;
  1134. {
  1135.     char *t;
  1136.  
  1137.     if (!strcmp(name, "GEM")) {
  1138.         init_is_gem = 1;
  1139.         goto setup_init;
  1140.     } 
  1141.     if (!strcmp(name, "INIT")) {
  1142.         init_is_gem = 0;
  1143. setup_init:
  1144.         if (!*val) return;
  1145.         t = kmalloc(strlen(val)+1);
  1146.         if (!t) return;
  1147.         strcpy(t, val);
  1148.         init_prg = t;
  1149.         while (*t && !isspace(*t)) t++;
  1150. /* get the command tail, too */
  1151.         if (*t) {
  1152.             *t++ = 0;
  1153.             strncpy(init_tail+1, t, 125);
  1154.             init_tail[126] = 0;
  1155.             init_tail[0] = strlen(init_tail+1);
  1156.         }
  1157.         return;
  1158.     }
  1159.     if (!strcmp(name, "CON")) {
  1160.         FILEPTR *f;
  1161.         int i;
  1162.  
  1163.         f = do_open(val, O_RDWR, 0, (XATTR *)0);
  1164.         if (f) {
  1165.             for (i = -1; i < 2; i++) {
  1166.                 do_close(curproc->handle[i]);
  1167.                 curproc->handle[i] = f;
  1168.                 f->links++;
  1169.             }
  1170.             f->links--;    /* correct for overdoing it */
  1171.         }
  1172.         return;
  1173.     }
  1174.     if (!strcmp(name, "PRN")) {
  1175.         FILEPTR *f;
  1176.  
  1177.         f = do_open(val, O_RDWR|O_CREAT|O_TRUNC, 0, (XATTR *)0);
  1178.         if (f) {
  1179.             do_close(curproc->handle[3]);
  1180.             do_close(curproc->prn);
  1181.             curproc->prn = curproc->handle[3] = f;
  1182.             f->links = 2;
  1183.         }
  1184.         return;
  1185.     }
  1186.     if (!strcmp(name, "BIOSBUF")) {
  1187.         if (*val == 'n' || *val == 'N') {
  1188.             if (bconbsiz) bflush();
  1189.             bconbdev = -1;
  1190.         }
  1191.         return;
  1192.     }
  1193.     if (!strcmp(name, "DEBUG_LEVEL")) {
  1194.         extern int debug_level;
  1195.         if (*val >= '0' && *val <= '9')
  1196.             debug_level = (int)atol(val);
  1197.         else ALERT("Bad arg to \"DEBUG_LEVEL\" in cnf file");
  1198.         return;
  1199.     }
  1200.     if (!strcmp(name, "DEBUG_DEVNO")) {
  1201.         extern int out_device;
  1202.         if (*val >= '0' && *val <= '9')
  1203.             out_device= (int)atol(val);
  1204.         else ALERT("Bad arg to \"DEBUG_DEVNO\" in cnf file");
  1205.         return;
  1206.     }
  1207.  
  1208. #ifdef FASTTEXT
  1209.     if (!strcmp(name, "HARDSCROLL")) {
  1210.         int i;
  1211.         extern int hardscroll;
  1212.  
  1213.         if (!strcmp(val, "AUTO")) {
  1214.             hardscroll = -1;
  1215.             return;
  1216.         }
  1217.         i = *val++;
  1218.         if (i < '0' || i > '9') return;
  1219.         hardscroll = i-'0';
  1220.         i = *val;
  1221.         if (i < '0' || i > '9') return;
  1222.         hardscroll = 10*hardscroll + i - '0';
  1223.         return;
  1224.     }
  1225. #endif
  1226.     if (!strcmp(name, "MAXMEM")) {
  1227.         long r;
  1228.  
  1229.         r = atol(val) * 1024L;
  1230.         if (r > 0)
  1231.             p_setlimit(2, r);
  1232.         return;
  1233.     }
  1234.     if (!strcmp(name, "SLICES")) {
  1235.         extern short time_slice;
  1236.  
  1237.         time_slice = atol(val);
  1238.         return;
  1239.     }
  1240.  
  1241.     if (!strcmp(name, "PSEUDODRIVES")) {
  1242.         FORCE("PSEUDODRIVES= no longer supported");
  1243.         return;
  1244.     }
  1245.     FORCE("Unknown variable `%s'", name);
  1246. }
  1247.  
  1248. /* Execute a line from the config file */
  1249. static void
  1250. do_line(line)
  1251.     char *line;
  1252. {
  1253.     char *cmd, *arg1, *arg2;
  1254.     char *newenv;
  1255.     char *t;
  1256.     int i;
  1257.  
  1258.     while (*line == ' ') line++;
  1259.     if (*line == '#') return;    /* ignore comments */
  1260.     if (!*line) return;        /* and also blank lines */
  1261.  
  1262.     cmd = line;
  1263. /* check for variable assignments (e.g. INIT=, etc.) */
  1264. /*
  1265.  * AGK: note we check for spaces whilst scanning so that an environment
  1266.  * variable may include an =, this has the unfortunate side effect that
  1267.  * the '=' _has_ to be concatenated to the variable name (INIT etc.)
  1268.  */
  1269.     for (t = cmd; *t && *t != ' '; t++) {
  1270.         if (*t == '=') {
  1271.             *t++ = 0;
  1272.             doset(cmd, t);
  1273.             return;
  1274.         }
  1275.     }
  1276.  
  1277. /* OK, assume a regular command; break it up into 'cmd', 'arg1', arg2' */
  1278.  
  1279.     while (*line && *line != ' ') line++;
  1280.     if (*line == ' ') {
  1281.         *line++ = 0;
  1282.         while (*line == ' ') line++;
  1283.     }
  1284.  
  1285.     if (!strcmp(cmd, "echo")) {
  1286.         c_conws(line); c_conws("\r\n");
  1287.         return;
  1288.     }
  1289.     arg1 = line;
  1290.     while (*line && *line != ' ') line++;
  1291.     if (*line) {
  1292.         *line++ = 0;
  1293.         while (*line == ' ') line++;
  1294.     }
  1295.     if (!strcmp(cmd, "cd")) {
  1296.         int drv;
  1297.         (void)d_setpath(arg1);
  1298.         drv = toupper(*arg1) - 'A';
  1299.         if (arg1[1] == ':') (void)d_setdrv(drv);
  1300.         return;
  1301.     }
  1302.     if (!strcmp(cmd, "exec")) {
  1303.         char cmdline[128];
  1304.         int i;
  1305.  
  1306.         i = strlen(line);
  1307.         if (i > 126) i = 126;
  1308.         cmdline[0] = i;
  1309.         strncpy(cmdline+1, line, i);
  1310.         cmdline[i+1] = 0;
  1311.         i = (int)p_exec(0, arg1, cmdline, init_env);
  1312.         if (i == -33) {
  1313.             FORCE("%s: file not found", arg1);
  1314.         } else if (i < 0) {
  1315.             FORCE("%s: error while attempting to execute", arg1);
  1316.         }
  1317.         return;
  1318.     }
  1319.     if (!strcmp(cmd, "setenv")) {
  1320.         if (strlen(arg1) + strlen(line) + 4 + (env_ptr - init_env) >
  1321.                              env_len) {
  1322.             long j;
  1323.  
  1324.             env_len += 1024;
  1325.             newenv = (char *)m_xalloc(env_len, 0x13);
  1326.             if (init_env) {
  1327.                 t = init_env;
  1328.                 j = env_ptr - init_env;
  1329.                 env_ptr = newenv;
  1330.                 for (i = 0; i < j; i++)
  1331.                     *env_ptr++ = *t++;
  1332.                 if (init_env)
  1333.                     m_free((virtaddr)init_env);
  1334.             } else {
  1335.                 env_ptr = newenv;
  1336.             }
  1337.             init_env = newenv;
  1338.         }
  1339.         while (*arg1) {
  1340.             *env_ptr++ = *arg1++;
  1341.         }
  1342.         *env_ptr++ = '=';
  1343.         while (*line) {
  1344.             *env_ptr++ = *line++;
  1345.         }
  1346.         *env_ptr++ = 0;
  1347.         *env_ptr = 0;
  1348.         return;
  1349.     }
  1350.  
  1351.     arg2 = line;
  1352.     while (*line && *line != ' ') line++;
  1353.     if (*line) {
  1354.         *line = 0;
  1355.     }
  1356.     if (!strcmp(cmd, "alias")) {
  1357.         int drv;
  1358.         long r;
  1359.         fcookie root_dir;
  1360.         extern int aliasdrv[];
  1361.  
  1362.         drv = toupper(*arg1) - 'A';
  1363.         if (drv < 0 || drv >= NUM_DRIVES) {
  1364.             ALERT("Bad drive (%c:) in alias", drv+'A');
  1365.             return;
  1366.         }
  1367.         r = path2cookie(arg2, NULL, &root_dir);
  1368.         if (r) {
  1369.             ALERT("alias: TOS error %ld while looking for %s",
  1370.                 r, arg2);
  1371.             return;
  1372.         }
  1373.         aliasdrv[drv] = root_dir.dev + 1;
  1374.         *((long *)0x4c2L) |= (1L << drv);
  1375.         release_cookie(&curproc->curdir[drv]);
  1376.         dup_cookie(&curproc->curdir[drv], &root_dir);
  1377.         release_cookie(&curproc->root[drv]);
  1378.         curproc->root[drv] = root_dir;
  1379.         return;
  1380.     }
  1381.     if (!strcmp(cmd, "sln")) {
  1382.         (void)f_symlink(arg1, arg2);
  1383.         return;
  1384.     }
  1385.     if (!strcmp(cmd, "ren")) {
  1386.         (void)f_rename(0, arg1, arg2);
  1387.         return;
  1388.     }
  1389.     FORCE("syntax error in mint.cnf near: %s", cmd);
  1390. }
  1391.  
  1392. #undef BUF
  1393. #undef LINE
  1394.  
  1395. #define BUF 512
  1396. #define LINE 256
  1397.  
  1398. void
  1399. load_config()
  1400. {
  1401.     int fd;
  1402.     long r;
  1403.     char buf[BUF+1], c;
  1404.     char line[LINE+1];
  1405.     char *from;
  1406.     int count = 0;
  1407.  
  1408.     fd = (int) f_open("mint.cnf", 0);
  1409.     if (fd < 0)
  1410.         fd = (int) f_open("\\mint\\mint.cnf", 0);
  1411.     if (fd < 0)
  1412.         fd = (int) f_open("\\multitos\\mint.cnf", 0);
  1413.     if (fd < 0) return;
  1414.     buf[BUF] = 0;
  1415.     from = &buf[BUF];
  1416.     line[LINE] = 0;
  1417.  
  1418.     for(;;) {
  1419.         c = *from++;
  1420.         if (!c) {
  1421.             r = f_read(fd, (long)BUF, buf);
  1422.             if (r <= 0) break;
  1423.             buf[r] = 0;
  1424.             from = buf;
  1425.         } else if (c == '\r') {
  1426.             continue;
  1427.         } else if (c == '\n') {
  1428.             line[count] = 0;
  1429.             do_line(line);
  1430.             count = 0;
  1431.         } else {
  1432.             if (count < LINE) {
  1433.                 line[count++] = c;
  1434.             }
  1435.         }
  1436.     }
  1437.     if (count) {
  1438.         line[count] = 0;
  1439.         do_line(line);
  1440.     }
  1441.     f_close(fd);
  1442. }
  1443.  
  1444. /*
  1445.  * run programs in the AUTO folder that appear after MINT.PRG
  1446.  * some things to watch out for:
  1447.  * (1) make sure GEM isn't active
  1448.  * (2) make sure there really is a MINT.PRG in the auto folder
  1449.  */
  1450.  
  1451. /*
  1452.  * some global variables used to see if GEM is active
  1453.  */
  1454. static short aes_intout[64];
  1455. static short aes_dummy[64];
  1456. static short aes_globl[15];
  1457. static short aes_cntrl[6] = { 10, 0, 1, 0, 0 };
  1458.  
  1459. short *aes_pb[6] = { aes_cntrl, aes_globl, aes_dummy, aes_intout,
  1460.              aes_dummy, aes_dummy };
  1461.  
  1462. /* check for whether GEM is active; remember, this *must* be done in
  1463.  * user mode
  1464.  */
  1465.  
  1466. static int
  1467. check_for_gem()
  1468. {
  1469.     call_aes(aes_pb);    /* does an appl_init */
  1470.     return aes_globl[0];
  1471. }
  1472.  
  1473. static void
  1474. run_auto_prgs()
  1475. {
  1476.     DTABUF *dta;
  1477.     long r;
  1478.     static char pathspec[32] = "\\AUTO\\";
  1479.     short runthem = 0;    /* set to 1 after we find MINT.PRG */
  1480.  
  1481. /* if the AES is running, don't check AUTO */
  1482.  
  1483.     if (gem_active) {
  1484.         return;
  1485.     }
  1486.  
  1487. /* OK, now let's run through \\AUTO looking for
  1488.  * programs...
  1489.  */
  1490.     dta = (DTABUF *)f_getdta();
  1491.     r = f_sfirst("\\AUTO\\*.PRG", 0);
  1492.     while (r >= 0) {
  1493.         if (!strcmp(dta->dta_name, "MINT.PRG") ||
  1494.             !strcmp(dta->dta_name, "MINTNP.PRG"))
  1495.             runthem = 1;
  1496.         else if (runthem) {
  1497.             strcpy(pathspec+6, dta->dta_name);
  1498.             (void)p_exec(0, pathspec, (char *)"", init_env);
  1499.         }
  1500.         r = f_snext();
  1501.     }
  1502. }
  1503.